using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes;
using JGSY.CMS.LowCode.Platform.Infrastructure.Configuration;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Configuration;

/// <summary>
/// 增强版 Serilog 配置管理器
/// 提供更完善的日志配置，整合到现有的配置系统中
/// </summary>
public static class EnhancedSerilogConfigurator
{
    private static readonly object _heavyLock = new();
    private static bool _heavyAttached = false;
    private static string? _actualDbType;
    private static IConfiguration? _configurationRef;
    private static bool _deferredEnabled;

    /// <summary>
    /// 为 WebApplicationBuilder 配置增强版 Serilog
    /// 这是推荐的配置方式，结合了 Microsoft.Extensions.Logging 和 Serilog 的优势
    /// </summary>
    /// <param name="builder">Web应用构建器</param>
    public static void ConfigureEnhancedSerilog(WebApplicationBuilder builder)
    {
        // 读取与数据库相关参数
        var forceToEnable = ConfigurationAccessor.SerilogForceToEnable;
        var databaseSerialType = ConfigurationAccessor.SerilogDatabaseSerialType;
        var mainDatabaseType = ConfigurationAccessor.MainDatabaseType;

        _actualDbType = forceToEnable && !string.IsNullOrEmpty(databaseSerialType)
            ? databaseSerialType
            : mainDatabaseType ?? "Sqlite";
        _configurationRef = builder.Configuration;
        _deferredEnabled = builder.Configuration.GetValue("Logging:Deferred:Enable", true);

        // 快速启动模式：或 显式禁用延迟 => 直接加载全部 sinks
        var isFast = StartupOptimizations.IsFastStartupEnabled(builder.Configuration) ||
                     string.Equals(builder.Environment.EnvironmentName, "Fast", StringComparison.OrdinalIgnoreCase);

        if (!_deferredEnabled || isFast)
        {
            var fullConfig = CreateFullLoggerConfiguration(builder.Configuration, _actualDbType);
            Log.Logger = fullConfig.CreateLogger();
        }
        else
        {
            // 初始仅 Console，最小阻塞
            var baseConfig = CreateBaseConfiguration(builder.Configuration)
                .WriteTo.Console(
                    outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}",
                    theme: Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme.Code);
            Log.Logger = baseConfig.CreateLogger();
            Log.Information("[DeferredLogging] 已启用，初始仅 Console，重型 sink 将后台附加…");
        }

        builder.Host.UseSerilog(Log.Logger, dispose: true);
        builder.Services.AddSingleton<Serilog.ILogger>(Log.Logger);
    }

    /// <summary>
    /// 创建 Serilog 配置
    /// </summary>
    /// <param name="configuration">应用配置</param>
    /// <param name="dbType">数据库类型</param>
    /// <returns>LoggerConfiguration</returns>
    private static LoggerConfiguration CreateFullLoggerConfiguration(IConfiguration configuration, string dbType)
    {
        var loggerConfig = CreateBaseConfiguration(configuration)
            // 控制台
            .WriteTo.Console(
                outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}",
                theme: Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme.Code)
            // 文件输出
            .WriteTo.File(
                path: "logs/app-.log",
                rollingInterval: RollingInterval.Day,
                retainedFileCountLimit: 30,
                fileSizeLimitBytes: 50 * 1024 * 1024,
                rollOnFileSizeLimit: true,
                outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}")
            // 错误单独文件
            .WriteTo.Logger(lc => lc
                .Filter.ByIncludingOnly(e => e.Level >= LogEventLevel.Error)
                .WriteTo.File(
                    path: "logs/errors-.log",
                    rollingInterval: RollingInterval.Day,
                    retainedFileCountLimit: 90,
                    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}"));

        EnhancedConfigurationProcessor.ConfigureSerilogDatabase(loggerConfig, dbType);
        return loggerConfig;
    }

    private static LoggerConfiguration CreateBaseConfiguration(IConfiguration configuration)
    {
        return new LoggerConfiguration()
            .MinimumLevel.Information()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
            .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
            .MinimumLevel.Override("System", LogEventLevel.Warning)
            .Enrich.FromLogContext()
            .Enrich.WithProperty("Application", "JGSY.CMS.LowCode.Platform")
            .Enrich.WithProperty("Environment", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production");
    }

    /// <summary>
    /// 附加重型日志 sinks（文件 / 错误文件 / 数据库 等）。可被后台 HostedService 调用。
    /// </summary>
    public static void AttachHeavySinks()
    {
        if (!_deferredEnabled) return; // 未启用
        if (_heavyAttached) return;
        if (_configurationRef is null || string.IsNullOrEmpty(_actualDbType)) return;

        lock (_heavyLock)
        {
            if (_heavyAttached) return;
            try
            {
                var fullConfig = CreateFullLoggerConfiguration(_configurationRef, _actualDbType!);
                // 保留现有 logger 的一些上下文？（Serilog 全局切换即可）
                Log.Logger = fullConfig.CreateLogger();
                _heavyAttached = true;
                Log.Information("[DeferredLogging] 重型日志 sink 已附加 (文件/错误/数据库)。");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[DeferredLogging] 附加重型日志失败: {ex.Message}");
            }
        }
    }

    /// <summary>
    /// 获取针对特定类型的强类型日志记录器（Microsoft.Extensions.Logging）
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <param name="serviceProvider">服务提供程序</param>
    /// <returns>强类型日志记录器</returns>
    public static ILogger<T> GetLogger<T>(IServiceProvider serviceProvider)
    {
        return serviceProvider.GetRequiredService<ILogger<T>>();
    }

    /// <summary>
    /// 获取 Serilog 日志记录器（用于需要 Serilog 特有功能的场景）
    /// </summary>
    /// <param name="serviceProvider">服务提供程序</param>
    /// <returns>Serilog日志记录器</returns>
    public static Serilog.ILogger GetSerilogLogger(IServiceProvider serviceProvider)
    {
        return serviceProvider.GetRequiredService<Serilog.ILogger>();
    }

    /// <summary>
    /// 配置日志记录的性能优化
    /// </summary>
    /// <param name="services">服务集合</param>
    public static void AddLoggingOptimizations(IServiceCollection services)
    {
        // 配置日志记录性能选项
        services.Configure<LoggerFilterOptions>(options =>
        {
            // 减少不必要的日志记录
            options.AddFilter("Microsoft.EntityFrameworkCore.Database.Command", LogLevel.Warning);
            options.AddFilter("Microsoft.EntityFrameworkCore.Infrastructure", LogLevel.Warning);
            options.AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", LogLevel.Warning);
            options.AddFilter("Microsoft.AspNetCore.Mvc.Infrastructure", LogLevel.Warning);
            options.AddFilter("Microsoft.AspNetCore.Routing", LogLevel.Warning);
        });
    }

    /// <summary>
    /// 应用程序关闭时清理 Serilog
    /// </summary>
    public static void CloseSerilog()
    {
        Log.CloseAndFlush();
    }
}

/// <summary>
/// 日志记录扩展方法
/// </summary>
public static class LoggingExtensions
{
    /// <summary>
    /// 记录性能测量
    /// </summary>
    /// <param name="logger">日志记录器</param>
    /// <param name="operationName">操作名称</param>
    /// <returns>性能测量器</returns>
    public static IDisposable MeasurePerformance(this Microsoft.Extensions.Logging.ILogger logger, string operationName)
    {
        return new PerformanceMeasurer(logger, operationName);
    }

    /// <summary>
    /// 记录结构化用户操作
    /// </summary>
    /// <param name="logger">日志记录器</param>
    /// <param name="userId">用户ID</param>
    /// <param name="action">操作</param>
    /// <param name="details">详细信息</param>
    public static void LogUserAction(this Microsoft.Extensions.Logging.ILogger logger, string userId, string action, object? details = null)
    {
        logger.LogInformation("用户操作: {UserId} 执行了 {Action}，详细信息: {@Details}", 
            userId, action, details ?? "无");
    }

    /// <summary>
    /// 记录数据库操作
    /// </summary>
    /// <param name="logger">日志记录器</param>
    /// <param name="operation">操作类型</param>
    /// <param name="table">表名</param>
    /// <param name="recordId">记录ID</param>
    /// <param name="elapsedMs">耗时毫秒</param>
    public static void LogDatabaseOperation(this Microsoft.Extensions.Logging.ILogger logger, string operation, string table, 
        object? recordId = null, long? elapsedMs = null)
    {
        if (elapsedMs.HasValue)
        {
            logger.LogInformation("数据库操作: {Operation} 表 {Table}，记录ID: {RecordId}，耗时: {ElapsedMs}ms", 
                operation, table, recordId, elapsedMs);
        }
        else
        {
            logger.LogInformation("数据库操作: {Operation} 表 {Table}，记录ID: {RecordId}", 
                operation, table, recordId);
        }
    }

    /// <summary>
    /// 记录API调用
    /// </summary>
    /// <param name="logger">日志记录器</param>
    /// <param name="method">HTTP方法</param>
    /// <param name="path">请求路径</param>
    /// <param name="statusCode">状态码</param>
    /// <param name="elapsedMs">耗时毫秒</param>
    /// <param name="userId">用户ID</param>
    public static void LogApiCall(this Microsoft.Extensions.Logging.ILogger logger, string method, string path, 
        int statusCode, long elapsedMs, string? userId = null)
    {
        var logLevel = statusCode >= 400 ? LogLevel.Warning : LogLevel.Information;
        
        logger.Log(logLevel, "API调用: {Method} {Path} 响应 {StatusCode}，耗时: {ElapsedMs}ms，用户: {UserId}", 
            method, path, statusCode, elapsedMs, userId ?? "匿名");
    }
}

/// <summary>
/// 性能测量器
/// </summary>
internal class PerformanceMeasurer : IDisposable
{
    private readonly Microsoft.Extensions.Logging.ILogger _logger;
    private readonly string _operationName;
    private readonly System.Diagnostics.Stopwatch _stopwatch;

    public PerformanceMeasurer(Microsoft.Extensions.Logging.ILogger logger, string operationName)
    {
        _logger = logger;
        _operationName = operationName;
        _stopwatch = System.Diagnostics.Stopwatch.StartNew();
        
        _logger.LogDebug("开始操作: {OperationName}", operationName);
    }

    public void Dispose()
    {
        _stopwatch.Stop();
        var elapsedMs = _stopwatch.ElapsedMilliseconds;
        
        var logLevel = elapsedMs > 1000 ? LogLevel.Warning : LogLevel.Information;
        
        _logger.Log(logLevel, "完成操作: {OperationName}，耗时: {ElapsedMs}ms", 
            _operationName, elapsedMs);
    }
}
